home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / dev / devSCSIDisk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  30.1 KB  |  1,050 lines

  1. /* 
  2.  * devScsiDisk.c --
  3.  *
  4.  *      SCSI Command formatter for SCSI type 0 (Direct Access Devices.) 
  5.  *    This file implements the BlockDevice interface to SCSI disk.
  6.  *
  7.  * Copyright 1986 Regents of the University of California
  8.  * All rights reserved.
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software and its documentation for any purpose and without
  11.  * fee is hereby granted, provided that the above copyright
  12.  * notice appear in all copies.  The University of California
  13.  * makes no representations about the suitability of this
  14.  * software for any purpose.  It is provided "as is" without
  15.  * express or implied warranty.
  16.  */
  17.  
  18. #ifndef lint
  19. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/dev/devSCSIDisk.c,v 9.22 92/03/20 13:47:48 jhh Exp $ SPRITE (Berkeley)";
  20. #endif not lint
  21.  
  22.  
  23. #include <sprite.h>
  24. #include <stdio.h>
  25. #include <fs.h>
  26. #include <dev.h>
  27. #include <devInt.h>
  28. #include <sys/scsi.h>
  29. #include <scsiDevice.h>
  30. #include <devDiskLabel.h>
  31. #include <devDiskStats.h>
  32. #include <devBlockDevice.h>
  33. #include <stdlib.h>
  34. #include <bstring.h>
  35. #include <dev/scsi.h>
  36. #include <dbg.h>
  37. #include <fsdm.h>
  38.  
  39. typedef struct DiskMap {
  40.     int     firstSector;
  41.     int     sizeInSectors;
  42. } DiskMap;
  43.  
  44. /*
  45.  * Maximum size of the disk in sectors. 
  46.  */
  47. #define    MAX_DISK_SIZE    0x7fffffff
  48. /*
  49.  * State info for an SCSI Disk.  This gets allocated and filled in by
  50.  * the attach procedure. 
  51.  */
  52. typedef struct ScsiDisk {
  53.     DevBlockDeviceHandle blockHandle; /* Must be FIRST field. */
  54.     ScsiDevice    *devPtr;          /* SCSI Device we have open. */
  55.     int            partition;  /* What partition we want. A partition number
  56.                  * of -1 means the whole disk.
  57.                  */
  58.     int sizeInSectors;        /* The number of sectors on disk. This number is
  59.                  * MAX_DISK_SIZE if partition == -1. */
  60.     DiskMap map[DEV_NUM_DISK_PARTS];    /* The partition map */
  61.     DevDiskStats *diskStatsPtr;    /* Area for disk stats. */    
  62.     int retries;        /* Number of times current command has been
  63.                  * retried. */
  64. } ScsiDisk;
  65.  
  66. typedef struct ScsiDiskCmd {
  67.     ScsiDisk    *diskPtr;    /* Target disk of command. */
  68.     ScsiCmd    scsiCmd;    /* SCSI command to send to disk. */
  69. } ScsiDiskCmd;
  70.  
  71.  
  72. #define    SCSI_DISK_SECTOR_SIZE    DEV_BYTES_PER_SECTOR
  73.  
  74. #define    RequestDone(requestPtr,status,byteCount) \
  75.     ((requestPtr)->doneProc)((requestPtr),(status),(byteCount))
  76.  
  77. static ReturnStatus DiskError _ARGS_((ScsiDevice *devPtr,
  78.                 ScsiCmd *scsiCmdPtr));
  79. static Boolean    ScsiDiskIdleCheck _ARGS_((ClientData clientData,
  80.                 DevDiskStats *diskStatsPtr));
  81. static int DiskDoneProc _ARGS_((struct ScsiCmd *scsiCmdPtr, 
  82.                 ReturnStatus status, int statusByte, 
  83.                 int byteCount, int senseLength, 
  84.                 Address senseDataPtr));
  85.  
  86.  
  87. /*
  88.  *----------------------------------------------------------------------
  89.  *
  90.  * FillInLabel --
  91.  *
  92.  *    Read the label of the disk and record the partitioning info.
  93.  *
  94.  * Results:
  95.  *    None.
  96.  *
  97.  * Side effects:
  98.  *    Define the disk partitions that determine which part of the
  99.  *    disk each different disk device uses.
  100.  *
  101.  *----------------------------------------------------------------------
  102.  */
  103. static ReturnStatus
  104. FillInLabel(devPtr,diskPtr)
  105.     ScsiDevice         *devPtr; /* SCSI Handle for device. */
  106.     ScsiDisk         *diskPtr;  /* Disk state stucture to read label. */
  107. {
  108.     register ReturnStatus    status;
  109.     ScsiCmd            labelReadCmd;
  110.     Sun_DiskLabel        *sunLabelPtr;
  111.     Dec_DiskLabel        *decLabelPtr;
  112.     Fsdm_DiskHeader        *diskHdrPtr;
  113.     char            labelBuffer[SCSI_DISK_SECTOR_SIZE];
  114.     int                byteCount;
  115.     int                part;
  116.     Boolean            printLabel = FALSE;
  117.  
  118. #ifdef DEBUG
  119.     printLabel = TRUE;
  120. #endif
  121.  
  122.     /*
  123.      * The label of a SCSI disk normally resides in the first sector. Format
  124.      * and send a SCSI READ command to fetch the sector.
  125.      */
  126.     DevScsiGroup0Cmd(devPtr, SCSI_READ, 0, 1,&labelReadCmd);
  127.     labelReadCmd.buffer = labelBuffer;
  128.     labelReadCmd.dataToDevice = FALSE;
  129.     labelReadCmd.bufferLen = SCSI_DISK_SECTOR_SIZE;
  130.     diskPtr->retries = 0;
  131.     status = DevScsiSendCmdSync(devPtr,&labelReadCmd, &byteCount);
  132.     if ((status == SUCCESS) && (byteCount < sizeof(Sun_DiskLabel))) {
  133.     status = DEV_EARLY_CMD_COMPLETION;
  134.     }
  135.     if (status != SUCCESS) {
  136.     return(status);
  137.     }
  138.     sunLabelPtr = (Sun_DiskLabel *) labelBuffer;
  139.     if (sunLabelPtr->magic == SUN_DISK_MAGIC) {
  140.     /*
  141.      * XXX - Should really check if label is valid.
  142.      */
  143.     if (printLabel) {
  144.         printf("%s: %s\n", devPtr->locationName, sunLabelPtr->asciiLabel);
  145.     }
  146.  
  147.     diskPtr->sizeInSectors = sunLabelPtr->numSectors * 
  148.                 sunLabelPtr->numHeads * sunLabelPtr->numCylinders;
  149.     
  150.     if (printLabel) {
  151.         printf(" Partitions ");
  152.     }
  153.     for (part = 0; part < DEV_NUM_DISK_PARTS; part++) {
  154.         diskPtr->map[part].firstSector = sunLabelPtr->map[part].cylinder *
  155.                          sunLabelPtr->numHeads * 
  156.                          sunLabelPtr->numSectors;
  157.         diskPtr->map[part].sizeInSectors =
  158.                     sunLabelPtr->map[part].numBlocks;
  159.         if (printLabel) {
  160.         printf(" (%d,%d)", diskPtr->map[part].firstSector,
  161.                        diskPtr->map[part].sizeInSectors);
  162.         }
  163.     }
  164.     if (printLabel) {
  165.         printf("\n");
  166.     }
  167.  
  168.     return(SUCCESS);
  169.     }
  170.     /*
  171.      * The disk isn't in SUN format so try Sprite format.
  172.      */
  173.     diskHdrPtr = (Fsdm_DiskHeader *)labelBuffer;
  174.     if (diskHdrPtr->magic == FSDM_DISK_MAGIC) {
  175.     /*
  176.      * XXX - Should really check if label is valid.
  177.      */
  178.     if (printLabel) {
  179.         printf("%s: %s\n", devPtr->locationName, diskHdrPtr->asciiLabel);
  180.     }
  181.  
  182.     diskPtr->sizeInSectors = diskHdrPtr->numSectors * 
  183.                  diskHdrPtr->numHeads *
  184.                      diskHdrPtr->numCylinders;
  185.  
  186.     if (printLabel) {
  187.         printf(" Partitions ");
  188.     }
  189.     for (part = 0; part < DEV_NUM_DISK_PARTS; part++) {
  190.         diskPtr->map[part].firstSector = 
  191.                 diskHdrPtr->map[part].firstCylinder *
  192.                 diskHdrPtr->numHeads * diskHdrPtr->numSectors;
  193.         diskPtr->map[part].sizeInSectors =
  194.                 diskHdrPtr->map[part].numCylinders *
  195.                 diskHdrPtr->numHeads * diskHdrPtr->numSectors;
  196.         if (printLabel) {
  197.         printf(" (%d,%d)", diskPtr->map[part].firstSector,
  198.                    diskPtr->map[part].sizeInSectors);
  199.         }
  200.     }
  201.     if (printLabel) {
  202.         printf("\n");
  203.     }
  204.     return(SUCCESS);
  205.     }
  206.     /*
  207.      * The disk isn't in SUN or Sprite format so try Dec format.
  208.      * We have to read the right sector first.
  209.      */
  210.     DevScsiGroup0Cmd(devPtr, SCSI_READ, DEC_LABEL_SECTOR, 1,&labelReadCmd);
  211.     labelReadCmd.buffer = labelBuffer;
  212.     labelReadCmd.dataToDevice = FALSE;
  213.     labelReadCmd.bufferLen = SCSI_DISK_SECTOR_SIZE;
  214.     diskPtr->retries = 0;
  215.     status = DevScsiSendCmdSync(devPtr,&labelReadCmd, &byteCount);
  216.     if ((status == SUCCESS) && (byteCount < sizeof(Dec_DiskLabel))) {
  217.     status = DEV_EARLY_CMD_COMPLETION;
  218.     }
  219.     if (status != SUCCESS) {
  220.     return(status);
  221.     }
  222.     decLabelPtr = (Dec_DiskLabel *) labelBuffer;
  223.     if (decLabelPtr->magic == DEC_LABEL_MAGIC) {
  224.     /*
  225.      * XXX - Should really check if label is valid.
  226.      */
  227.     if (decLabelPtr->spriteMagic != FSDM_DISK_MAGIC) {
  228.         printf("Disk needs Sprite-modified Dec label\n");
  229.     }
  230.     if (decLabelPtr->version != DEC_LABEL_VERSION) {
  231.         printf("Disk label version mismatch: %x vs %x\n",
  232.             decLabelPtr->version, DEC_LABEL_VERSION);
  233.     }
  234.     if (printLabel) {
  235.         printf("%s: %s\n", devPtr->locationName, decLabelPtr->asciiLabel);
  236.     }
  237.  
  238.     diskPtr->sizeInSectors = decLabelPtr->numSectors * 
  239.                 decLabelPtr->numHeads * decLabelPtr->numCylinders;
  240.     
  241.     if (printLabel) {
  242.         printf(" Partitions ");
  243.     }
  244.     for (part = 0; part < DEV_NUM_DISK_PARTS; part++) {
  245.         diskPtr->map[part].firstSector =
  246.             decLabelPtr->map[part].offsetBytes / DEV_BYTES_PER_SECTOR;
  247.         diskPtr->map[part].sizeInSectors =
  248.             decLabelPtr->map[part].numBytes / DEV_BYTES_PER_SECTOR;
  249.         if (printLabel) {
  250.         printf(" (%d,%d)", diskPtr->map[part].firstSector,
  251.                        diskPtr->map[part].sizeInSectors);
  252.         }
  253.     }
  254.     if (printLabel) {
  255.         printf("\n");
  256.     }
  257.  
  258.     return(SUCCESS);
  259.     }
  260.     return(FAILURE);
  261. }
  262.  
  263. /*
  264.  *----------------------------------------------------------------------
  265.  *
  266.  * ScsiDiskIdleCheck --
  267.  *
  268.  *    Routine for the Disk Stats module to use to determine the idleness
  269.  *    for a disk.
  270.  *
  271.  * Results:
  272.  *    TRUE if the disk pointed to by clientData is idle, FALSE otherwise.
  273.  *
  274.  * Side effects:
  275.  *    None.
  276.  *
  277.  *----------------------------------------------------------------------
  278.  */
  279. /*ARGSUSED*/
  280. static Boolean
  281. ScsiDiskIdleCheck(clientData, diskStatsPtr) 
  282.     ClientData        clientData;        /* Unused for SCSI disks. */
  283.     DevDiskStats    *diskStatsPtr;
  284. {
  285.     Boolean        retVal;
  286.  
  287.     MASTER_LOCK(&(diskStatsPtr->mutex));
  288.     retVal = !(diskStatsPtr->busy);
  289.     MASTER_UNLOCK(&(diskStatsPtr->mutex));
  290.  
  291.     return retVal;
  292.  
  293. }
  294.  
  295. /*
  296.  *----------------------------------------------------------------------
  297.  *
  298.  * InitDisk --
  299.  *
  300.  *    Initialize the device driver state for a SCSI Disk. 
  301.  *
  302.  * Results:
  303.  *    The ScsiDisk structure. NIL - if there is an error attaching the
  304.  *    disk.
  305.  *
  306.  * Side effects:
  307.  *    The disk's label is read and saved in a ScsiDisk structure.  This
  308.  *    is allocated here.
  309.  *
  310.  *----------------------------------------------------------------------
  311.  */
  312. static ScsiDisk *
  313. InitDisk(devPtr,readLabel)
  314.     ScsiDevice    *devPtr; /* SCSI Handle for device. */
  315.     Boolean    readLabel;   /* TRUE if we should read and fill in label 
  316.                   * fields. */
  317. {
  318.     ScsiDisk    disk, *diskPtr;
  319.     ReturnStatus status;
  320.     int        retry = 3;
  321.     bzero((char *) &disk, sizeof(ScsiDisk));
  322.     /*
  323.      * Check that the disk is on-line.  
  324.      * We do this check twice because it appears that dec rz55 
  325.      * drives always indicate that they are ready after powerup,
  326.      * even if their not.
  327.      */
  328.     status = DevScsiTestReady(devPtr);
  329.     status = DevScsiTestReady(devPtr);
  330.     if (status != SUCCESS) {
  331.     if (status != DEV_OFFLINE) {
  332.         return((ScsiDisk *) NIL);
  333.     }
  334.     /*
  335.      * Do this loop a few times because Quantum drives appear to respond
  336.      * to the first start request before they are actually on-line.
  337.      */
  338.     while (retry > 0) {
  339.         /*
  340.          * Try and start the unit.
  341.          */
  342.         status = DevScsiStartStopUnit(devPtr, TRUE);
  343.         if (status != SUCCESS) {
  344.         return((ScsiDisk *) NIL);
  345.         }
  346.         /*
  347.          * Make sure the unit is ready.
  348.          */
  349.         status = DevScsiTestReady(devPtr);
  350.         if (status == SUCCESS) {
  351.         break;
  352.         }
  353.         retry--;
  354.     }
  355.     }
  356.     disk.devPtr = devPtr;
  357.     if (readLabel) {
  358.     status = FillInLabel(devPtr,&disk);
  359.     if (status != SUCCESS) {
  360.         return((ScsiDisk *) NIL);
  361.     }
  362.     } else {
  363.     disk.sizeInSectors = MAX_DISK_SIZE;
  364.     }
  365.  
  366.     /*
  367.      * Return a malloced copy of the structure we filled in.
  368.      */
  369.     diskPtr = (ScsiDisk *) malloc(sizeof(ScsiDisk));
  370.     *diskPtr = disk;
  371.     return(diskPtr);
  372. }
  373.  
  374. /*
  375.  *----------------------------------------------------------------------
  376.  *
  377.  * DiskDoneProc --
  378.  *
  379.  *    Call back routine for request to SCSI Disk. 
  380.  *
  381.  * Results:
  382.  *    None.
  383.  *
  384.  * Side effects:
  385.  *    Request call may be woken up.
  386.  *
  387.  *----------------------------------------------------------------------
  388.  */
  389. /*ARGSUSED*/
  390. static int
  391. DiskDoneProc(scsiCmdPtr, status, statusByte, byteCount, senseLength, 
  392.          senseDataPtr)
  393.     ScsiCmd    *scsiCmdPtr;    /* Request that finished. */
  394.     ReturnStatus  status;    /* Error of request. */
  395.     unsigned char statusByte;    /* SCSI status byte of request. */
  396.     int        byteCount;    /* Number of bytes transferred. */
  397.     int        senseLength;    /* Length of sense data returned. */
  398.     Address    senseDataPtr;    /* Sense data. */
  399. {
  400.     DevBlockDeviceRequest *requestPtr;
  401.     ScsiDisk    *diskPtr;
  402.  
  403.     requestPtr = (DevBlockDeviceRequest *) (scsiCmdPtr->clientData);
  404.     diskPtr = ((ScsiDiskCmd *) (requestPtr->ctrlData))->diskPtr;
  405.  
  406.     MASTER_LOCK(&(diskPtr->diskStatsPtr->mutex));
  407.     diskPtr->diskStatsPtr->busy--;
  408.     if (requestPtr->operation == FS_READ) {
  409.     diskPtr->diskStatsPtr->diskStats.diskReads += 
  410.                 byteCount/DEV_BYTES_PER_SECTOR;
  411.     } else {
  412.     diskPtr->diskStatsPtr->diskStats.diskWrites += 
  413.                 byteCount/DEV_BYTES_PER_SECTOR;
  414.     }
  415.     MASTER_UNLOCK(&(diskPtr->diskStatsPtr->mutex));
  416.  
  417.     /*
  418.      * We need to copy the sense data out of the buffer given to us by
  419.      * the HBA into the buffer in ScsiCmd.  Someday we should get rid
  420.      * of all sense buffers except those in the ScsiCmd.  JHH
  421.      */
  422.  
  423.      bcopy((char *) senseDataPtr, scsiCmdPtr->senseBuffer, senseLength);
  424.      scsiCmdPtr->senseLen = senseLength;
  425.      scsiCmdPtr->statusByte = statusByte;
  426.  
  427.     /*
  428.      * If request suffered an HBA error or got no error we notify the
  429.      * caller that the request is done.
  430.      */
  431.     if ((status != SUCCESS) || (statusByte == 0)) {
  432.     RequestDone(requestPtr,status,byteCount);
  433.     return 0;
  434.     }
  435.     /*
  436.      * Otherwise we have a SCSI command that returned an error. 
  437.      */
  438.     status = DiskError(diskPtr->devPtr, scsiCmdPtr);
  439.     /*
  440.      * If the device was reset then retry the command.  This isn't quite
  441.      * correct, but works in the majority of cases because most of the
  442.      * time the scsi bus is reset by the device driver.  In reality the
  443.      * bus could be reset because someone replaced one drive with another.
  444.      * If you really want to handle that situation then you have to pass
  445.      * the status up to the higher level code and let it decide what to do.
  446.      * Of course that means you have to handle it in many different places,
  447.      * whereas this solution only requires modification to this routine.
  448.      * JHH 6/7/91
  449.      *
  450.      * If the command aborted then retry it as well. 
  451.      */
  452.     if ((status == DEV_RESET) || (status == DEV_RETRY_ERROR)) {
  453.     if (diskPtr->retries < 4) {
  454.         printf("WARNING: device %s, command did not complete. Retrying.\n", 
  455.         diskPtr->devPtr->locationName);
  456.         scsiCmdPtr->senseLen = sizeof(scsiCmdPtr->senseBuffer);
  457.         DevScsiSendCmd(diskPtr->devPtr, scsiCmdPtr);
  458.         diskPtr->retries++;
  459.     } else {
  460.         printf("WARNING: device %s, too many retries\n", 
  461.         diskPtr->devPtr->locationName);
  462.         RequestDone(requestPtr,status,byteCount);
  463.     }
  464.     } else {
  465.     RequestDone(requestPtr,status,byteCount);
  466.     }
  467.     return 0;
  468.  
  469. }
  470.  
  471. /*
  472.  *----------------------------------------------------------------------
  473.  *
  474.  * SendCmdToDevice --
  475.  *
  476.  *    Translate a Block Device request into and SCSI command and send it
  477.  *    to the disk device.
  478.  *
  479.  * Results:
  480.  *    SUCCESS is the command is sent otherwise a Sprite Error code.
  481.  *
  482.  * Side effects:
  483.  *    Disk may be read or written.
  484.  *
  485.  *----------------------------------------------------------------------
  486.  */
  487. static ReturnStatus
  488. SendCmdToDevice(diskPtr, requestPtr, firstSector, lengthInSectors)
  489.     ScsiDisk    *diskPtr;
  490.     DevBlockDeviceRequest *requestPtr;
  491.     unsigned int    firstSector;
  492.     unsigned int    lengthInSectors;
  493. {
  494.     int        cmd;
  495.     ScsiDiskCmd     *diskCmdPtr = (ScsiDiskCmd *) (requestPtr->ctrlData);
  496.     ReturnStatus status;
  497.  
  498.     if (sizeof(ScsiDiskCmd) > sizeof((requestPtr->ctrlData))) {
  499.     panic("ScsiDISK: command block bigger than controller data\n");
  500.     return FAILURE;
  501.     }
  502.     if (firstSector <= 0x1fffff) {
  503.     cmd = (requestPtr->operation == FS_READ) ? SCSI_READ : SCSI_WRITE;
  504.     status = DevScsiGroup0Cmd(diskPtr->devPtr,cmd, firstSector, 
  505.             lengthInSectors, &(diskCmdPtr->scsiCmd));
  506.     if (status != SUCCESS) {
  507.         return FAILURE;
  508.     }
  509.     } else {
  510.     ScsiReadExtCmd    *cmdPtr;
  511.     /*
  512.      * The offset is too big for the standard 6-byte SCSI read and
  513.      * write commands.  We have to use the extended version.  Perhaps
  514.      * we should always use the extended version?
  515.      */
  516.     if (lengthInSectors > 0xffff) {
  517.         printf("SendCmdToDevice: too many sectors (%d > %d)\n",
  518.         lengthInSectors, 0xffff);
  519.         return FAILURE;
  520.     }
  521.     bzero((char *) &(diskCmdPtr->scsiCmd), sizeof(ScsiCmd));
  522.     diskCmdPtr->scsiCmd.commandBlockLen = sizeof(ScsiReadExtCmd);
  523.     cmdPtr = (ScsiReadExtCmd *) (diskCmdPtr->scsiCmd.commandBlock);
  524.     cmdPtr->command = (requestPtr->operation == FS_READ) ? 
  525.         SCSI_READ_EXT : SCSI_WRITE_EXT;
  526.     cmdPtr->unitNumber = diskPtr->devPtr->LUN;
  527.     cmdPtr->highAddr = ((firstSector >> 24) & 0xff);
  528.     cmdPtr->highMidAddr = ((firstSector >> 16) & 0xff);
  529.     cmdPtr->lowMidAddr = ((firstSector >> 8) & 0xff);
  530.     cmdPtr->lowAddr = ((firstSector) & 0xff);
  531.     cmdPtr->highCount = ((lengthInSectors >> 8) & 0xff);
  532.     cmdPtr->lowCount = ((lengthInSectors) & 0xff);
  533.     }
  534.     diskCmdPtr->scsiCmd.buffer = requestPtr->buffer;
  535.     diskCmdPtr->scsiCmd.bufferLen = lengthInSectors * SCSI_DISK_SECTOR_SIZE;
  536.     diskCmdPtr->scsiCmd.dataToDevice = (requestPtr->operation == FS_WRITE);
  537.     diskCmdPtr->scsiCmd.doneProc = DiskDoneProc;
  538.     diskCmdPtr->scsiCmd.clientData = (ClientData) requestPtr;
  539.     diskCmdPtr->scsiCmd.senseLen = sizeof(diskCmdPtr->scsiCmd.senseBuffer);
  540.     diskCmdPtr->diskPtr = diskPtr;
  541.  
  542.     MASTER_LOCK(&(diskPtr->diskStatsPtr->mutex));
  543.     diskPtr->diskStatsPtr->busy++;
  544.     MASTER_UNLOCK(&(diskPtr->diskStatsPtr->mutex));
  545.  
  546.     diskPtr->retries = 0;
  547.     DevScsiSendCmd(diskPtr->devPtr,&(diskCmdPtr->scsiCmd));
  548.     return SUCCESS;
  549. }
  550.  
  551. /*
  552.  *----------------------------------------------------------------------
  553.  *
  554.  * DiskError --
  555.  *
  556.  *    Map SCSI errors indicated by the sense data into Sprite ReturnStatus
  557.  *    and error message. This proceedure handles two types of 
  558.  *    sense data Class 0 and class 7.
  559.  *
  560.  * Results:
  561.  *    A sprite error code.
  562.  *
  563.  * Side effects:
  564.  *    None.
  565.  *
  566.  *----------------------------------------------------------------------
  567.  */
  568. static ReturnStatus
  569. DiskError(devPtr, scsiCmdPtr)
  570.     ScsiDevice     *devPtr;    /* SCSI device that's complaining. */
  571.     ScsiCmd    *scsiCmdPtr;    /* SCSI command that had the problem. */
  572. {
  573.     unsigned char statusByte = scsiCmdPtr->statusByte;
  574.     ReturnStatus status;
  575.     ScsiStatus *statusPtr = (ScsiStatus *) &statusByte;
  576.     ScsiClass0Sense *sensePtr = (ScsiClass0Sense *) scsiCmdPtr->senseBuffer;
  577.     int    senseLength = scsiCmdPtr->senseLen;
  578.     char    *name = devPtr->locationName;
  579.     char    errorString[MAX_SCSI_ERROR_STRING];
  580.  
  581.     /*
  582.      * Check for status byte to see if the command returned sense
  583.      * data. If no sense data exists then we only have the status
  584.      * byte to look at.
  585.      */
  586.     if (!statusPtr->check) {
  587.     if (SCSI_RESERVED_STATUS(statusByte) || statusPtr->intStatus) {
  588.         printf("Warning: SCSI Disk at %s unknown status byte 0x%x\n",
  589.            name, statusByte);
  590.         return SUCCESS;
  591.     } 
  592.     if (statusPtr->busy) {
  593.         return DEV_OFFLINE;
  594.     }
  595.     return SUCCESS;
  596.     }
  597.     if (senseLength == 0) {
  598.      printf("Warning: SCSI Disk %s error: no sense data\n", name);
  599.      return DEV_NO_SENSE;
  600.     }
  601.     if (DevScsiMapClass7Sense(senseLength, scsiCmdPtr->senseBuffer,
  602.         &status, errorString)) {
  603.     if (errorString[0]) {
  604.          printf("Warning: SCSI Disk %s error: %s\n", name, errorString);
  605.     }
  606.     return status;
  607.     }
  608.  
  609.     /*
  610.      * If its not a class 7 error it must be Old style sense data..
  611.      */
  612.     if (sensePtr->error == SCSI_NO_SENSE_DATA) {        
  613.     status = SUCCESS;
  614.     } else {
  615.     int class = (sensePtr->error & 0x70) >> 4;
  616.     int code = sensePtr->error & 0xF;
  617.     int addr;
  618.     addr = ((unsigned int) sensePtr->highAddr << 16) |
  619.         ((unsigned int) sensePtr->midAddr << 8) |
  620.         sensePtr->lowAddr;
  621.     printf("Warning: SCSI disk at %s sense error (%d-%d) at <%x> ",
  622.             name, class, code, addr);
  623.     if (devScsiNumErrors[class] > code) {
  624.         printf("%s", devScsiErrors[class][code]);
  625.      }
  626.      printf("\n");
  627.      status = DEV_HARD_ERROR;
  628.     }
  629.     return status;
  630. }
  631. /*
  632.  * This code is for the raid people to test out HBA/disks pairs 
  633.  * by bypassing most of Sprite.
  634.  * Mendel 9/12/89
  635.  */
  636.  
  637. #include <dev/hbatest.h>
  638. /*ARGSUSED*/
  639. static int
  640. DiskHBATestDoneProc(scsiCmdPtr, status, statusByte, byteCount, senseLength, 
  641.          senseDataPtr)
  642.     ScsiCmd    *scsiCmdPtr;    /* Request that finished. */
  643.     ReturnStatus  status;    /* Error of request. */
  644.     unsigned char statusByte;    /* SCSI status byte of request. */
  645.     int        byteCount;    /* Number of bytes transferred. */
  646.     int        senseLength;    /* Length of sense data returned. */
  647.     Address    senseDataPtr;    /* Sense data. */
  648. {
  649.     ReturnStatus *errorStatusPtr = (ReturnStatus *) (scsiCmdPtr->clientData);
  650.     ScsiStatus *statusPtr = (ScsiStatus *) &statusByte;
  651.     char    errorString[MAX_SCSI_ERROR_STRING];
  652.     ScsiClass0Sense *sensePtr = (ScsiClass0Sense *) senseDataPtr;
  653.     /*
  654.      * Check for status byte to see if the command returned sense
  655.      * data. If no sense data exists then we only have the status
  656.      * byte to look at.
  657.      */
  658.     if ((status == SUCCESS) && !statusPtr->check) {
  659.     return 0;
  660.     }
  661.     if (senseLength == 0) {
  662.      printf("Warning: SCSI Disk error: no sense data\n");
  663.      *errorStatusPtr = DEV_NO_SENSE;
  664.      return DEV_NO_SENSE;
  665.     }
  666.     if (DevScsiMapClass7Sense(senseLength, senseDataPtr,&status, errorString)) {
  667.     if (errorString[0]) {
  668.          printf("Warning: SCSI Disk  error: %s\n", errorString);
  669.     }
  670.         *errorStatusPtr = status;
  671.     return status;
  672.     }
  673.  
  674.     /*
  675.      * If its not a class 7 error it must be Old style sense data..
  676.      */
  677.     if (sensePtr->error == SCSI_NO_SENSE_DATA) {        
  678.     status = SUCCESS;
  679.     } else {
  680.     int class = (sensePtr->error & 0x70) >> 4;
  681.     int code = sensePtr->error & 0xF;
  682.     int addr;
  683.     addr = ((unsigned int) sensePtr->highAddr << 16) |
  684.         ((unsigned int) sensePtr->midAddr << 8) |
  685.         sensePtr->lowAddr;
  686.     printf("Warning: SCSI disk sense error (%d-%d) at <%x> ",
  687.             class, code, addr);
  688.     if (devScsiNumErrors[class] > code) {
  689.         printf("%s", devScsiErrors[class][code]);
  690.      }
  691.      printf("\n");
  692.      status = DEV_HARD_ERROR;
  693.     }
  694.     *errorStatusPtr = status;
  695.     return 0;
  696. }
  697.  
  698. /*
  699.  *----------------------------------------------------------------------
  700.  *
  701.  * IOControlProc --
  702.  *
  703.  *      Do a special operation on a raw SCSI Disk.
  704.  *
  705.  * Results:
  706.  *      None.
  707.  *
  708.  * Side effects:
  709.  *      None.
  710.  *
  711.  *----------------------------------------------------------------------
  712.  */
  713.  
  714. /*ARGSUSED*/
  715. static ReturnStatus
  716. IOControlProc(handlePtr, ioctlPtr, replyPtr)
  717.     DevBlockDeviceHandle    *handlePtr; /* Handle pointer of device. */
  718.     Fs_IOCParam *ioctlPtr;    /* Standard I/O Control parameter block */
  719.     Fs_IOReply *replyPtr;    /* Size of outBuffer and returned signal */
  720. {
  721.      ScsiDisk    *diskPtr = (ScsiDisk *) handlePtr;
  722.      ReturnStatus    status = FAILURE;
  723.  
  724.      if ((ioctlPtr->command & ~0xffff) == IOC_SCSI) {
  725.      status = DevScsiIOControl(diskPtr->devPtr, ioctlPtr, replyPtr);
  726.      return status;
  727.  
  728.      }
  729.      switch (ioctlPtr->command) {
  730.     case    IOC_REPOSITION:
  731.         /*
  732.          * Reposition is ok
  733.          */
  734.         return(SUCCESS);
  735.         /*
  736.          * No disk specific bits are set this way.
  737.          */
  738.     case    IOC_GET_FLAGS:
  739.     case    IOC_SET_FLAGS:
  740.     case    IOC_SET_BITS:
  741.     case    IOC_CLEAR_BITS:
  742.         return(SUCCESS);
  743.  
  744.     case    IOC_GET_OWNER:
  745.     case    IOC_SET_OWNER:
  746.         return(GEN_NOT_IMPLEMENTED);
  747.  
  748.     case    IOC_TRUNCATE:
  749.         return(GEN_INVALID_ARG);
  750.  
  751.     case    IOC_LOCK:
  752.     case    IOC_UNLOCK:
  753.         return(GEN_NOT_IMPLEMENTED);
  754.  
  755.     case    IOC_NUM_READABLE:
  756.         return(GEN_NOT_IMPLEMENTED);
  757.  
  758.     case    IOC_MAP:
  759.         return(GEN_NOT_IMPLEMENTED);
  760.  
  761.     /*
  762.      * This code is for the raid people to test out HBA/disks pairs 
  763.      * by bypassing most of Sprite.
  764.      * Mendel 9/12/89
  765.      */
  766.     case   IOC_HBA_DISK_IO_TEST: {
  767.         register int count, i;
  768.         register DevHBADiskTest  *cmds;
  769.         ScsiCmd    *scsiCmds;
  770.         ReturnStatus       errorStatus;
  771.         static  char *dmaMem, *dmem;
  772.         char *mem;
  773.         static int referCount = 0;
  774.  
  775.         if ((ioctlPtr->inBufSize % sizeof(DevHBADiskTest)) || 
  776.         !ioctlPtr->inBufSize) {
  777.         return(GEN_INVALID_ARG);
  778.         }
  779.         count = ioctlPtr->inBufSize / sizeof(DevHBADiskTest);
  780.         cmds = (DevHBADiskTest  * ) ioctlPtr->inBuffer;
  781.         mem = malloc(sizeof(ScsiCmd)*count);
  782.         if (referCount == 0) { 
  783.             dmem = malloc(128*1024);
  784. #if defined(sun4) || defined(sun3)
  785.             dmaMem = VmMach_DMAAlloc(128*1024, dmem);
  786.             if (dmaMem == (Address) NIL) {
  787.             panic("IOControlProc: unable to allocate dma memory.");
  788.             }
  789. #else
  790.             dmaMem = dmem;
  791. #endif
  792.         } 
  793.         referCount++;
  794.         scsiCmds = (ScsiCmd *) (mem);
  795.         errorStatus = 0;
  796.         for (i = 0; i < count; i++) {
  797.         DevScsiGroup0Cmd(diskPtr->devPtr, 
  798.                 cmds[i].writeOperation ? SCSI_WRITE : SCSI_READ,
  799.                 cmds[i].firstSector, cmds[i].lengthInSectors,
  800.                 &(scsiCmds[i]));
  801.         scsiCmds[i].buffer = dmaMem;
  802.         scsiCmds[i].bufferLen = cmds[i].lengthInSectors * 
  803.                             SCSI_DISK_SECTOR_SIZE;
  804.             scsiCmds[i].dataToDevice = cmds[i].writeOperation;
  805.         scsiCmds[i].clientData = (ClientData) &errorStatus;
  806.             scsiCmds[i].doneProc = DiskHBATestDoneProc;
  807.             scsiCmds[i].senseLen = sizeof(scsiCmds[i].senseBuffer);
  808.         if (i < count - 1) {
  809.             diskPtr->retries = 0;
  810.             DevScsiSendCmd(diskPtr->devPtr, &(scsiCmds[i]));
  811.         } else {
  812.             int    byteCount;
  813.             diskPtr->retries = 0;
  814.             status = DevScsiSendCmdSync(diskPtr->devPtr,
  815.                 &(scsiCmds[i]),&byteCount);
  816.         }
  817.        }
  818.        referCount--;
  819.        if (referCount == 0) {
  820. #if defined(sun4) || defined(sun3)
  821.            VmMach_DMAFree(128*1024, dmaMem);
  822. #endif
  823.            free(dmem);
  824.        }
  825.        free(mem);
  826.        if (status) {
  827.            return status;
  828.         }
  829.        return errorStatus;
  830.  
  831.     }
  832.     case   IOC_HBA_DISK_UNIT_TEST: {
  833.         register int count, i;
  834.         register ScsiCmd    *scsiCmds;
  835.         ReturnStatus       errorStatus;
  836.  
  837.         if (ioctlPtr->inBufSize != sizeof(int)) {
  838.         return(GEN_INVALID_ARG);
  839.         }
  840.         count = *(int *) ioctlPtr->inBuffer;
  841.         if ((count < 0) || (count > MAX_HBA_UNIT_TESTS)) {
  842.         return(GEN_INVALID_ARG);
  843.         }
  844.         scsiCmds = (ScsiCmd *) malloc(sizeof(ScsiCmd)*count);
  845.         errorStatus = 0;
  846.         for (i = 0; i < count; i++) {
  847.         DevScsiGroup0Cmd(diskPtr->devPtr, SCSI_TEST_UNIT_READY,
  848.                 0, 0, scsiCmds + i);
  849.         scsiCmds[i].buffer = (char *) NIL;
  850.         scsiCmds[i].bufferLen = 0;
  851.             scsiCmds[i].dataToDevice = 0;
  852.         scsiCmds[i].clientData = (ClientData) &errorStatus;
  853.             scsiCmds[i].doneProc = DiskHBATestDoneProc;
  854.             scsiCmds[i].senseLen = sizeof(scsiCmds[i].senseBuffer);
  855.         if (i < count - 1) {
  856.             diskPtr->retries = 0;
  857.             DevScsiSendCmd(diskPtr->devPtr, &(scsiCmds[i]));
  858.         } else {
  859.             int    byteCount;
  860.             diskPtr->retries = 0;
  861.             status = DevScsiSendCmdSync(diskPtr->devPtr,
  862.                 &(scsiCmds[i]), &byteCount);
  863.         }
  864.        }
  865.        free((char *) scsiCmds);
  866.        if (status) {
  867.            return status;
  868.         }
  869.        return errorStatus;
  870.  
  871.     }
  872.     default:
  873.         return(GEN_INVALID_ARG);
  874.     }
  875. }
  876.  
  877. /*
  878.  *----------------------------------------------------------------------
  879.  *
  880.  * ReleaseProc --
  881.  *
  882.  *    Block device release proc.
  883.  *
  884.  * Results:
  885.  *    None.
  886.  *
  887.  * Side effects:
  888.  *    None.
  889.  *
  890.  *----------------------------------------------------------------------
  891.  */
  892. /*ARGUSED*/
  893. static ReturnStatus
  894. ReleaseProc(handlePtr)
  895.     DevBlockDeviceHandle    *handlePtr; /* Handle pointer of device. */
  896. {
  897.     ReturnStatus status;    
  898.     ScsiDisk    *diskPtr = (ScsiDisk *) handlePtr;
  899.  
  900.     status = DevScsiReleaseDevice(diskPtr->devPtr);
  901.     DevDiskUnregister(diskPtr->diskStatsPtr);
  902.     free((char *) diskPtr);
  903.  
  904.     return status;
  905. }
  906.  
  907. /*
  908.  *----------------------------------------------------------------------
  909.  *
  910.  * BlockIOProc --
  911.  *
  912.  *    Convert a Block device IO request in a SCSI command block and 
  913.  *    submit it to the HBA.
  914.  *
  915.  * Results:
  916.  *    The return code from the I/O operation.
  917.  *
  918.  * Side effects:
  919.  *    The disk write, if operation == FS_WRITE.
  920.  *
  921.  *----------------------------------------------------------------------
  922.  */
  923.  
  924. static ReturnStatus
  925. BlockIOProc(handlePtr, requestPtr) 
  926.     DevBlockDeviceHandle    *handlePtr; /* Handle pointer of device. */
  927.     DevBlockDeviceRequest *requestPtr; /* IO Request to be performed. */
  928. {
  929.     ReturnStatus status;    
  930.     ScsiDisk    *diskPtr = (ScsiDisk *) handlePtr;
  931.     unsigned int    firstSector, lengthInSectors, sizeInSectors;
  932.  
  933.  
  934.     if (!((requestPtr->operation == FS_READ) ||
  935.           (requestPtr->operation == FS_WRITE))) {
  936.     panic("Unknown operation %d in ScsiDisk blockIOProc.\n", 
  937.         requestPtr->operation);
  938.     return DEV_INVALID_ARG;
  939.     }
  940.     /*
  941.      * Insure that the request is within the bounds of the partition.
  942.      */
  943.     firstSector = requestPtr->startAddress/DEV_BYTES_PER_SECTOR;
  944.     lengthInSectors = requestPtr->bufferLen/DEV_BYTES_PER_SECTOR;
  945.     sizeInSectors = (diskPtr->partition == WHOLE_DISK_PARTITION) ?
  946.                 diskPtr->sizeInSectors   :
  947.                     diskPtr->map[diskPtr->partition].sizeInSectors;
  948.     if (firstSector >= sizeInSectors) {
  949.     /*
  950.      * The offset is past the end of the partition.
  951.      */
  952.     RequestDone(requestPtr,SUCCESS,0);
  953.     return SUCCESS;
  954.     } 
  955.     if (((firstSector + lengthInSectors - 1) >= sizeInSectors)) {
  956.     /*
  957.      * The transfer is at the end of the partition.  Reduce the
  958.      * sector count so there is no overrun.
  959.      */
  960.     lengthInSectors = sizeInSectors - firstSector;
  961.     } 
  962.     if (diskPtr->partition != WHOLE_DISK_PARTITION) {
  963.     /*
  964.      * Relocate the disk address to be relative to this partition.
  965.      */
  966.     firstSector += diskPtr->map[diskPtr->partition].firstSector;
  967.     }
  968.  
  969.     status = SendCmdToDevice(diskPtr, requestPtr, firstSector, lengthInSectors);
  970.     return(status);
  971. }
  972.  
  973. /*
  974.  *----------------------------------------------------------------------
  975.  *
  976.  * DevScsiDiskAttach --
  977.  *
  978.  *    Attach a SCSI Disk device to the system.
  979.  *
  980.  * Results:
  981.  *    The DevBlockDeviceHandle of the device.
  982.  *
  983.  * Side effects:
  984.  *    None.
  985.  *
  986.  *----------------------------------------------------------------------
  987.  */
  988.  
  989. DevBlockDeviceHandle *
  990. DevScsiDiskAttach(devicePtr)
  991.     Fs_Device    *devicePtr;    /* The device to attach. */
  992. {
  993.     ScsiDevice    *devPtr;
  994.     ScsiDisk    *diskPtr;
  995.  
  996.     /*
  997.      * Ask the HBA to set up the path to the device. For the time being
  998.      * we will not sort the disk requests.
  999.      */
  1000.     devPtr = DevScsiAttachDevice(devicePtr, DEV_QUEUE_FIFO_INSERT);
  1001.     if (devPtr == (ScsiDevice *) NIL) {
  1002.     return (DevBlockDeviceHandle *) NIL;
  1003.     }
  1004.     /*
  1005.      * Determine the type of device from the inquiry return by the
  1006.      * attach. Reject device if not of disk type. If the target 
  1007.      * didn't respond to the INQUIRY command we assume that it
  1008.      * just a stupid disk.
  1009.      */
  1010.     if ((devPtr->inquiryLength > 0) &&
  1011.     (((ScsiInquiryData *) (devPtr->inquiryDataPtr))->type != 
  1012.                             SCSI_DISK_TYPE)) {
  1013.     (void) DevScsiReleaseDevice(devPtr);
  1014.     return (DevBlockDeviceHandle *) NIL;
  1015.     }
  1016.     devPtr->errorProc = DiskError;
  1017.     /*
  1018.      * Initialize the ScsiDisk structure. We don't need to read the label
  1019.      * if the user is opening the device in raw (non partitioned) mode.
  1020.      */
  1021.     diskPtr = InitDisk(devPtr,DISK_IS_PARTITIONED(devicePtr));
  1022.     if (diskPtr == (ScsiDisk *) NIL) {
  1023.     return (DevBlockDeviceHandle *) NIL;
  1024.     }
  1025.     /*
  1026.      * Register this disk with the Disk stat routines.
  1027.      */
  1028.     {
  1029.     Fs_Device rawDevice;
  1030.  
  1031.     rawDevice = *devicePtr;
  1032.     rawDevice.unit = rawDevice.unit & ~0xf;
  1033.     diskPtr->diskStatsPtr = DevRegisterDisk(&rawDevice,
  1034.                           devPtr->locationName,
  1035.                           ScsiDiskIdleCheck, 
  1036.                           (ClientData) diskPtr);
  1037.     }
  1038.     diskPtr->partition = DISK_IS_PARTITIONED(devicePtr) ? 
  1039.                     DISK_PARTITION(devicePtr) :
  1040.                     WHOLE_DISK_PARTITION;
  1041.     diskPtr->blockHandle.blockIOProc = BlockIOProc;
  1042.     diskPtr->blockHandle.releaseProc = ReleaseProc;
  1043.     diskPtr->blockHandle.IOControlProc = IOControlProc;
  1044.     diskPtr->blockHandle.minTransferUnit = SCSI_DISK_SECTOR_SIZE;
  1045.     diskPtr->blockHandle.maxTransferSize = devPtr->maxTransferSize;
  1046.     return (DevBlockDeviceHandle *) diskPtr;
  1047. }
  1048.  
  1049.  
  1050.